﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SpreadsheetGear;
using Sustainalytics.Governance.BusinessLogic;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities.Governance;
using System.Configuration;
using System.Reflection;
using Sustainalytics.DataLayer.ConnectionStrings;
using Sustainalytics.Entities.ConnectionStrings;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.Entities;
using Sustainalytics.Governance.BusinessLogic.Model;

namespace UploadGovernanceMatrices
{
    class Program
    {
        private const string _regionGeneration = "r";
        private const string _tresholdGeneration = "t";
        static void Main(string[] args)
        {
            try
            {
                string path = null;
                bool regionFill = false;
                bool thresholdFill = false;

                switch (args.Length)
                {
                    case 0:
                    {
                        path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "WeightMatrix.xlsx");
                        Console.WriteLine("No path specified... trying {0}", path);
                        break;
                    }
                    case 1:
                    {
                        if (args[0] == _regionGeneration)
                        {
                            regionFill = true;
                        }
                        else
                            if (args[0] == _tresholdGeneration)
                            {
                                thresholdFill = true;
                            }
                            else
                            {
                                path = args[0];
                            }
                        break;
                    }
                    case 2:
                    {
                        CheckArgument(args[0], ref regionFill, ref thresholdFill, ref path);
                        CheckArgument(args[1], ref regionFill, ref thresholdFill, ref path);
                        break;
                    }
                    case 3:
                    {
                        CheckArgument(args[0], ref regionFill, ref thresholdFill, ref path);
                        CheckArgument(args[1], ref regionFill, ref thresholdFill, ref path);
                        CheckArgument(args[2], ref regionFill, ref thresholdFill, ref path);
                        break;
                    }
                    default:
                        throw new ArgumentException("Invalid number of params: only 2 should be specified!");
                }

                if (path!=null)
                    UploadFile(path);

                if (regionFill)
                    FillRegions();

                if (thresholdFill)
                    UploadThresholds();

                Console.WriteLine("Done!");
                Console.ReadLine();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
                Console.ReadLine();
            }
        }

        private static void CheckArgument(string arg, ref bool regionFill, ref bool thresholdFill, ref string path)
        {
            if (arg == _tresholdGeneration)
            {
                thresholdFill = true;
            }
            else if (arg == _regionGeneration)
            {
                regionFill = true;
            }
            else
            {
                path = arg;
            }
        }

        private static void FillRegions()
        {
            var clientPlatformCnx = ConfigurationManager.ConnectionStrings["ClientPlatform"].ConnectionString;
            var connectionStringsManager = ConnectionStringsManager.GetInstance(ConnectionStringsRepository.GetInstance(clientPlatformCnx),
                                                                                DateTime.Now, TimeSpan.FromHours(0), TimeSpan.FromMinutes(5));
            var connStringGovernanceDW = connectionStringsManager.GetConnectionString(ConnectionStringType.GovernanceDw);
            var connStringClientDW = connectionStringsManager.GetConnectionString(ConnectionStringType.ClientDw);

            var guidFront = Guid.NewGuid();
            var guidNord = Guid.NewGuid();
            var guidAP = Guid.NewGuid();
            var guidEE = Guid.NewGuid();
            var guidUSA = Guid.NewGuid();
            var regionAP = "AP";
            var regionEE = "EE";
            var regionNord = "NORD";
            var regionUSA = "USA";
            var regionFRONT = "FRONT";

            var regionRep = new RepositoryCollection<GovernanceRegion>(connStringGovernanceDW);
            var regions = new GovernanceRegion[]{ 
                new GovernanceRegion(){Id = guidAP, Code = regionAP}, 
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "AUSNZ"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "FRA"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "NL"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "BRZ"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "CAD"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "UKIRL"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "CHF"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "CHN"},
                new GovernanceRegion(){Id = guidEE, Code = regionEE},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "EUR"},
                new GovernanceRegion(){Id = guidFront, Code = regionFRONT},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "GER"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "HK"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "SEUR"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "IND"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "JPN"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "KOR"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "LA"},
                new GovernanceRegion(){Id = guidNord, Code = regionNord},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "SA"},
                new GovernanceRegion(){Id = Guid.NewGuid(), Code = "SG"},
                new GovernanceRegion(){Id = guidUSA, Code = regionUSA},
            };
            regionRep.DeleteAll();
            regionRep.CreateBatch(regions);

            //FillCompanies(connStringGovernanceDW, connStringClientDW, guidFront, guidNord, guidAP, guidEE, guidUSA, regionAP, regionEE, regionNord, regionUSA);

            var govCompRep = new RepositoryCollection<GovernanceCompanyProfile>(connStringGovernanceDW);
            var companies = govCompRep.ReadAll();
            var autoCompanies = companies.Where(c => c.Industry == "Automobiles");
            var banksCompanies = companies.Where(c => c.Industry == "Banks");

            autoCompanies.ToList().ForEach(c =>
            {
                c.RegionId = guidFront;
                c.RegionCode = regionFRONT;
                c.CreatedDate = DateTime.Now;
                c.IsValidReport = false;
                govCompRep.Update(c.Id, c);
            });

            banksCompanies.ToList().ForEach(c =>
            {
                c.RegionId = guidNord;
                c.RegionCode = regionNord;
                c.CreatedDate = DateTime.Now;
                c.IsValidReport = false;
                govCompRep.Update(c.Id, c);
            });

            var i = 0;
            companies.ToList().Where(c => !banksCompanies.Contains(c) && !autoCompanies.Contains(c)).ToList().ForEach(c =>
            {
                c.RegionId = i < 10 ? guidAP : (i < 20 ? guidEE : guidUSA);
                c.RegionCode = i < 10 ? regionAP : (i < 20 ? regionEE : regionUSA);
                c.CreatedDate = DateTime.Now;
                c.IsValidReport = false;
                govCompRep.Update(c.Id, c);
                i++;
            });
        }

        private static void FillCompanies(string connStringGovernanceDW, string connStringClientDW, Guid guidFront, Guid guidNord, Guid guidAP, Guid guidEE, Guid guidUSA, string regionAP, string regionEE, string regionNord, string regionUSA)
        {
            var corporateDataRep = new RepositoryCollection<CorporateData>(connStringClientDW);
            var companies = corporateDataRep.ReadAll();

            var autoCompanies = companies.Where(c => c.RootPeerGroup == "Automobiles");
            var banksCompanies = companies.Where(c => c.RootPeerGroup == "Banks");

            var govCompRep = new RepositoryCollection<GovernanceCompanyProfile>(connStringGovernanceDW);

            autoCompanies.ToList().ForEach(c =>
            {
                govCompRep.CreateOrUpdate(new GovernanceCompanyProfile()
                {
                    Id = c.Id,
                    CompanyName = c.CompanyName,
                    AnalystView = c.CompanyDescription,
                    CompanyNameSafeUrl = c.CompanyNameUrlFriendly,
                    CreatedDate = DateTime.Now,
                    Domicile = c.Address,
                    Employees = (int?)c.TotalEmployees,
                    Industry = c.RootPeerGroup,
                    UniverseIds = c.UniverseIds,
                    MarketCapitalization = c.MarketCapitalization,
                    RegionId = guidFront,
                    Ticker = c.MainTicker
                });
            });

            banksCompanies.ToList().ForEach(c =>
            {
                govCompRep.CreateOrUpdate(new GovernanceCompanyProfile()
                {
                    Id = c.Id,
                    CompanyName = c.CompanyName,
                    //AnalystView = c.CompanyDescription,
                    CompanyNameSafeUrl = c.CompanyNameUrlFriendly,
                    CreatedDate = DateTime.Now,
                    Domicile = c.Address,
                    Employees = (int?)c.TotalEmployees,
                    Industry = c.RootPeerGroup,
                    UniverseIds = c.UniverseIds,
                    MarketCapitalization = c.MarketCapitalization,
                    RegionId = guidNord,
                    RegionCode = regionNord,
                    Ticker = c.MainExchange + ":" + c.MainTicker,
                    IsValidReport = false
                });
            });
            var i = 0;
            companies.ToList().Where(c => !banksCompanies.Contains(c) && !autoCompanies.Contains(c)).ToList().ForEach(c =>
            {
                govCompRep.CreateOrUpdate(new GovernanceCompanyProfile()
                {
                    Id = c.Id,
                    CompanyName = c.CompanyName,
                    //AnalystView = c.CompanyDescription,
                    CompanyNameSafeUrl = c.CompanyNameUrlFriendly,
                    CreatedDate = DateTime.Now,
                    Domicile = c.Address,
                    Employees = (int?)c.TotalEmployees,
                    Industry = c.RootPeerGroup,
                    UniverseIds = c.UniverseIds,
                    MarketCapitalization = c.MarketCapitalization,
                    RegionId = i < 10 ? guidAP : (i < 20 ? guidEE : guidUSA),
                    RegionCode = i < 10 ? regionAP : (i < 20 ? regionEE : regionUSA),
                    Ticker = c.MainExchange + ":" + c.MainTicker,
                    IsValidReport = false
                });
                i++;
            });
        }

        private static bool UploadFile(string path)
        {
            var matricesWorkBook = Factory.GetWorkbookSet().Workbooks.Open(path);
            var matricesPreValidator = new GovernanceMatricesPreValidator(matricesWorkBook);
            MatrixDto indicatorMatrix;
            MatrixDto issueMatrix;
            List<MatrixDto> combinationMatrices;

            matricesPreValidator.Process(out indicatorMatrix, out issueMatrix, out combinationMatrices);

            var validator = new ValidateGovernanceWeightMatrix();
            if (!validator.Process(issueMatrix, indicatorMatrix, combinationMatrices))
            {
                Console.WriteLine("Invalid matrix! The validation errors are:");
                Console.WriteLine();
                validator.ErrorsMatrix.ForEach(x => { 
                    Console.Write(" - ");
                    Console.WriteLine(x.DisplayErrorWithExcelLocation); 
                });
                Console.WriteLine();
                return false;
            }

            var bytes = File.ReadAllBytes(path);
            var fileName = Path.GetFileName(path);
            var clientPlatformCnx = ConfigurationManager.ConnectionStrings["GovernanceInputFile"].ConnectionString;

            var repoGovInputFile = new RepositoryCollectionWithFile<GovernanceWeightMatrixInputFile>(clientPlatformCnx);
            repoGovInputFile.Create(new GovernanceWeightMatrixInputFile()
            {
                Id = Guid.NewGuid(),
                CreationTimestamp = DateTime.Now,
                Processed = null,
                FileName = fileName,
                FileContent = bytes,
                MimeType = "application/octet-stream",
                Name = "default"
            });

            return true;
        }

        private static void UploadThresholds()
        {
            var issues = ConfigurationManager.AppSettings["Issues"];
            if (issues == null)
            {
                throw new ApplicationException("There are no issues with thresholds in config to upload!");
            }
            var govThresholdList = new List<GovernanceAssesmentThreshold>();

            var issuesList = issues.Split(',');
            foreach (var issue in issuesList)
            {
                var thresholds = ConfigurationManager.AppSettings[issue];
                if (thresholds == null)
                {
                    throw new ApplicationException(String.Format("There are no thresholds for issue {0} in config to upload!", issue));
                }
                var thresholdList = thresholds.Split(',').ToList();
                var govAssesmentThreshold = new GovernanceAssesmentThreshold() { Id = Guid.NewGuid(), Number = issue, Thresholds = new List<int>() };
                thresholdList.ForEach(t =>
                {
                    int result;
                    if (!int.TryParse(t, out result))
                    {
                        throw new ApplicationException(String.Format("The thresholds for issue {0} in config are not all numeric!", issue));
                    }
                    govAssesmentThreshold.Thresholds.Add(result);
                });
                govThresholdList.Add(govAssesmentThreshold);
            }

            var governanceInputFileCnx = ConfigurationManager.ConnectionStrings["GovernanceInputFile"].ConnectionString;
            var repoAssesmentThreshold = new RepositoryCollection<GovernanceAssesmentThreshold>(governanceInputFileCnx);
            repoAssesmentThreshold.DeleteAll();
            repoAssesmentThreshold.CreateBatch(govThresholdList);
        }
    }
}
